package rmi.server;

import java.util.ArrayList;

import javax.persistence.NoResultException;
import javax.persistence.Query;

import model.Player;
import model.PlayerInterface;
import model.Settings;
import model.SettingsInterface;
import model.UserInterface;
import exception.UserAlreadyExistsException;

public class UserRemote extends Remote implements User
{
	private static UserRemote instance;
	
	public static UserRemote getInstance()
	{
		if (instance == null)
		{
			instance = new UserRemote();
		}
		
		return instance;
	}
	
	private UserRemote()
	{
		
	}
	
	final protected Object clone()
	{
		return null;
	}
	
	public PlayerInterface newPlayer(String username)
	{
		User user = (User) getUserByUsername(username);
		
		if (user != null)
		{
			return null;
		}
		
		PlayerInterface player = new Player(username);
		
		Settings settings = new Settings();
		setSettings(settings);
		player.setSettings(settings);
		
		return player;
	}
	
	// This method only updates the settings of the player instead of all the user properties.
	public void setSettings(PlayerInterface player)
	{
		setSettings(player.getSettings());
	}
	
	public void setSettings(SettingsInterface settings)
	{
		storeEntity(settings);
	}
	
	public void storeUser(UserInterface user)
	{
		storeEntity(user);
	}
	
	// Disable a players account.
	public void banPlayer(PlayerInterface player)
	{
		player.setBanned(true);
		
		storeEntity(player);
	}
	
	public UserInterface getDefaultUser()
	{
		return getUser("Kees", "test");
	}
	
	public UserInterface getUser(String username, char[] password)
	{
		return getUser(username, String.valueOf(password));
	}
	
	public UserInterface getUser(String username, String password)
	{
		// Create a query to fetch the player by username.
		Query getUser = entityManager.createQuery("SELECT user FROM User user WHERE username = :username");
		
		// Assign a value to the username parameter.
		getUser.setParameter("username", username);
		
		try
		{
			// Fetch the player from the query.
			UserInterface user = (UserInterface) getUser.getSingleResult();
			
			// Check if the given password is the same as the one stored in the database,
			// so we know it is the real user who logged in.
			if (user.equalsPassword(password))
			{
				return user;
			}
		}
		catch (NoResultException e)
		{
			// Nothing
		}
		
		return null;
	}

	public UserInterface getUserByUsername(String username)
	{
		Query getUser = entityManager.createQuery("SELECT user FROM User user WHERE username = :username");
		
		getUser.setParameter("username", username);
		
		try
		{
			return (UserInterface) getUser.getSingleResult();
		}
		catch (NoResultException e)
		{
			return null;
		}
	}
	
	public ArrayList<PlayerInterface> getPlayersByUsername(String username)
	{
		// Fetch all players in the database.
		Query getPlayersByUsername = entityManager.createQuery("SELECT player FROM Player player WHERE username LIKE :username");
		
		getPlayersByUsername.setParameter("username", username);
		
		return (ArrayList<PlayerInterface>) getPlayersByUsername.getResultList();
	}
	
	public ArrayList<PlayerInterface> getPlayers()
	{
		// Fetch all players in the database.
		return (ArrayList<PlayerInterface>) entityManager.createQuery("SELECT player FROM Player player").getResultList();
	}
	
	public void logout(UserInterface user)
	{
		ServerRemote.getInstance().removeClient(user);
	}
}
